using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Silverlight.Testing;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Rhino.Mocks;
using SLNGP.Common.Extensions;
using SLNGP.Core.Fitness;
using SLNGP.Core.Individuals;
using SLNGP.Core.Test;

namespace SLNGP.Test.CoreTests.Fitness
{
    [TestClass]
    [Tag("FitnessFunction")]
    public class FitnessFunction_Test : UnitTestBase<IFitnessFunction, FitnessFunction>
    {
        #region UnitTestBase methods
        [ClassInitialize]
        public static void ClassInitialize(TestContext testContext)
        {
            UnitTestBase<IFitnessFunction, FitnessFunction>.ClassInitialize(testContext);
        }

        [ClassCleanup]
        public static void ClassCleanup()
        {
            UnitTestBase<IFitnessFunction, FitnessFunction>.ClassCleanup();
        }

        [TestInitialize]
        public override void TestInitialize()
        {
            base.TestInitialize();
        }

        [TestCleanup]
        public override void TestCleanup()
        {
            base.TestCleanup();
        }
        #endregion UnitTestBase methods

        [TestMethod]
        public void OrderIsHigherIsBetter_IsBiggerWithNumbers_WorksLikeNormalComparison()
        {
            // state - OrderIsHigherIsBetter
            curElement.FitnessFunctionOrder = FitnessFunctionOrder.HigherIsBetter;

            // action - IsBiggerWithNumbers
            // Expectation - WorksLikeNormalComparison
            Assert.AreEqual(curElement.IsBigger(1, 2), 1 > 2);
            Assert.AreEqual(curElement.IsBigger(2, 3), 2 > 3);
            Assert.AreEqual(curElement.IsBigger(2, 1), 2 > 1);
            Assert.AreEqual(curElement.IsBigger(3, 2), 3 > 2);
        }

        [TestMethod]
        public void OrderIsLowerIsBetter_IsBiggerWithNumbers_WorksLikeNegativeComparison()
        {
            // state - OrderIsHigherIsBetter
            curElement.FitnessFunctionOrder = FitnessFunctionOrder.LowerIsBetter;

            // action - IsBiggerWithNumbers
            // Expectation - WorksLikeNormalComparison
            Assert.AreEqual(curElement.IsBigger(1, 2), 1 < 2);
            Assert.AreEqual(curElement.IsBigger(2, 3), 2 < 3);
            Assert.AreEqual(curElement.IsBigger(2, 1), 2 < 1);
            Assert.AreEqual(curElement.IsBigger(3, 2), 3 < 2);
        }

        [TestMethod]
        // Has a dependency on Generation
        public void HigherIsBetterWithMockGeneration_InitializeForEffectiveFitness_FitnessDataOnMockIsNull()
        {
            // state - HigherIsBetterWithMockGeneration
            curElement.FitnessFunctionOrder = FitnessFunctionOrder.HigherIsBetter;
            
            var stubGeneration = new Generation();

            // action - InitializeForEffectiveFitness
            curElement.InitializeForEffectiveFitness(stubGeneration);

            // Expectation - FitnessDataOnMockIsNull
            Assert.IsTrue(stubGeneration.FitnessData == null);
        }

        [TestMethod]
        // Has a dependency on Generation
        public void LowerIsBetterWithMockGenerationOf2Individual_InitializeForEffectiveFitness_FitnessDataOnMockIsMaxFitness()
        {
            // state - LowerIsBetterWithMockGenerationOf2Individual
            curElement.FitnessFunctionOrder = FitnessFunctionOrder.LowerIsBetter;
            var mockIndividual1 = mocks.DynamicMock<IIndividual>();
            var mockIndividual2 = mocks.DynamicMock<IIndividual>();
            using (mocks.Record())
            {
                SetupResult.For(mockIndividual1.Fitness).Return(10);
                SetupResult.For(mockIndividual2.Fitness).Return(20);
            }

            var stubGeneration = new Generation() { mockIndividual1, mockIndividual2 };

            // action - InitializeForEffectiveFitness
            curElement.InitializeForEffectiveFitness(stubGeneration);

            // Expectation - FitnessDataOnMockIsMaxFitness
            Assert.IsTrue(stubGeneration.FitnessData.As<int>() == 20);
        }

        [TestMethod]
        public void HigherIsBetterAndIndividualWith20Fitness_GetEffectiveFitness_Returns20()
        {
            // state - LowerIsBetterAndIndividualWith20Fitness
            curElement.FitnessFunctionOrder = FitnessFunctionOrder.HigherIsBetter;
            var mock = mocks.DynamicMock<IGeneration>();
            
            // action - GetEffectiveFitness
            var result = curElement.GetEffectiveFitness(20, mock);

            // Expectation - Returns20
            Assert.IsTrue(result == 20);
        }

        [TestMethod]
        public void LowerIsBetterAndIndividualWith20FitnessAnd50FitnessData_GetEffectiveFitness_Returns30()
        {
            // state - LowerIsBetterAndIndividualWith20Fitness
            curElement.FitnessFunctionOrder = FitnessFunctionOrder.LowerIsBetter;
            var mock = mocks.DynamicMock<IGeneration>();
            
            using (mocks.Record())
                Expect.Call(mock.FitnessData).Return(50);

            // action - GetEffectiveFitness
            var result = curElement.GetEffectiveFitness(20, mock);

            // Expectation - Returns20
            Assert.IsTrue(result == 30);
            mocks.VerifyAll();
        }

        [TestMethod]
        public void Ctor_FitnessOrder_IsHigherIsBetter()
        {
            // state - Ctor
            // action - FitnessOrder
            // Expectation - IsHigherIsBetter
            Assert.IsTrue(curElement.FitnessFunctionOrder == FitnessFunctionOrder.HigherIsBetter);
        }
    }
}
